package com.study.student_chuji.demos.config;

import com.study.student_chuji.demos.pojo.Permission;
import com.study.student_chuji.demos.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    // 权限集合：key为"请求方式:URL"（如"GET:/users"），value为对应权限
    private Map<String, Collection<ConfigAttribute>> permissionMap;

    @Autowired
    private PermissionService permissionService;

    // 初始化权限映射（启动时加载）
    @PostConstruct
    public void init() {
        loadPermissionMap();
    }

    /**
     * 加载所有权限，构建"请求方式:URL"→权限的映射（核心修复）
     */
    private void loadPermissionMap() {
        permissionMap = new HashMap<>();
        List<Permission> permissions = permissionService.getAllPermissions();

        for (Permission permission : permissions) {
            String url = permission.getUrl();
            String method = permission.getMethod();
            String permissionCode = permission.getPermissionCode();

            // 跳过无效权限配置
            if (url == null || url.trim().isEmpty() || permissionCode == null) {
                continue;
            }

            // 处理请求方式：空值用"*"（匹配所有方法），统一转为大写
            String methodKey = (method == null || method.trim().isEmpty())
                    ? "*"
                    : method.trim().toUpperCase();

            // 构建联合key："请求方式:URL"（如"GET:/users"、"POST:/users"）
            String key = methodKey + ":" + url.trim();

            // 同一key可对应多个权限（如同时需要user:view和user:manage）
            Collection<ConfigAttribute> configAttributes = permissionMap.getOrDefault(key, new ArrayList<>());
            configAttributes.add(new SecurityConfig(permissionCode));
            permissionMap.put(key, configAttributes);
        }
    }

    /**
     * 根据当前请求（URL+方法）获取所需权限（核心修复）
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        FilterInvocation fi = (FilterInvocation) object;
        HttpServletRequest request = fi.getHttpRequest();
        String requestUrl = request.getRequestURI().replaceAll("/$", ""); // 去除尾斜杠，统一格式
        String requestMethod = request.getMethod().toUpperCase(); // 获取请求方法（GET/POST等）

        AntPathMatcher pathMatcher = new AntPathMatcher();

        // 1. 优先精确匹配"请求方式:URL"（如"GET:/users"）
        String exactKey = requestMethod + ":" + requestUrl;
        if (permissionMap.containsKey(exactKey)) {
            return permissionMap.get(exactKey);
        }

        // 2. 通配符匹配（如"/users/**"），同时校验请求方式
        for (String patternKey : permissionMap.keySet()) {
            String[] keyParts = patternKey.split(":", 2);
            if (keyParts.length != 2) {
                continue;
            }
            String patternMethod = keyParts[0]; // 权限配置的方法（*或具体方法）
            String patternUrl = keyParts[1]; // 权限配置的URL（含通配符）

            // 方法匹配：*匹配所有，否则精确一致
            boolean methodMatch = "*".equals(patternMethod) || patternMethod.equals(requestMethod);
            // URL匹配：Ant风格通配符匹配
            boolean urlMatch = pathMatcher.match(patternUrl, requestUrl);

            if (methodMatch && urlMatch) {
                return permissionMap.get(patternKey);
            }
        }

        // 3. 未匹配到任何权限：默认需要登录
        return SecurityConfig.createList("ROLE_LOGIN");
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        // 返回所有权限（框架启动时校验用）
        return permissionMap.values().stream()
                .flatMap(Collection::stream)
                .collect(Collectors.toSet());
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}